using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

public partial class RobotManager : Node2D
{
    [Signal]
    public delegate void OnRobotMoveEndEventHandler(Robot robot);

    [Signal]
    public delegate void OnEnemyRoundEndEventHandler();

    [Signal]
    public delegate void OnRobotDestroyEventHandler(Robot robot);

    int InstanceId = 0;

    #region Prefab
    PackedScene AI_INITIATIVE = ResourceLoader.Load<PackedScene>(Path.AI_INITIATIVE);
    PackedScene AI_GUARD = ResourceLoader.Load<PackedScene>(Path.AI_GUARD);
    #endregion

    PackedScene robotPrefab = ResourceLoader.Load<PackedScene>(Path.ROBOT_SCENE);

    #region 子组件
    Node playerRoot;
    Node allyRoot;
    Node enemyRoot;

    Explosion explosion;
    #endregion

    static BaseMapManager MapManager => GameManager.Instance.LevelManager.MapManager;
    static VFXManager VFXManager => GameManager.Instance.LevelManager.VFXManager;
    static Cursor Cursor => GameManager.Instance.LevelManager.Cursor;

    void GetChildComponents()
    {
        playerRoot = GetNode("Player");
        allyRoot = GetNode("Ally");
        enemyRoot = GetNode("Enemy");
        explosion = GetNode<Explosion>("Explosion");
    }

    public override void _Ready()
    {
        base._Ready();
        GetChildComponents();
        levelManager = GetParent<BaseLevelManager>();
    }

    BaseLevelManager levelManager;

    public List<Robot> PlayerRobots = new();
    public List<Robot> AllyRobots = new();
    public List<Robot> EnemyRobots = new();

    public List<Robot> AllRobotList
    {
        get => PlayerRobots.Concat(AllyRobots).Concat(EnemyRobots).ToList();
    }


    public Robot CreateRobot(RobotModel mod, PilotModel pmd, bool isPlayer, bool isAlly, int level)
    {
        var robot = robotPrefab.Instantiate<Robot>();
        if (isAlly)
        {
            allyRoot.AddChild(robot);
            AllyRobots.Add(robot);
        }
        else if (isPlayer)
        {
            playerRoot.AddChild(robot);
            PlayerRobots.Add(robot);
        }
        else
        {
            enemyRoot.AddChild(robot);
            EnemyRobots.Add(robot);
            robot.ActionEnd += EnemyRobotActionEndHandler;
        }
        robot.InitData(mod, pmd, InstanceId++, isPlayer, isAlly, level);
        robot.Name = $"{mod.RobotName}_{InstanceId}";
        if (robot.Pilot.Skills.Count > 0)
        {
            foreach (var sid in robot.Pilot.Skills)
            {
                var skill = SkillManager.CreateSkill(sid);
                robot.Pilot.SkillList.Add(skill);
                skill.OwnerRobot = robot;
                // GD.Print($"{robot.Pilot.PilotName} 掌握了 {skill.SkillName} 技能");
            }
        }
        robot.OnMoveEnd += OnMoveEndHandler;
        robot.OnRobotDestroy += OnRobotDestroyHandler;
        return robot;
    }

    private void OnRobotDestroyHandler(Robot robot)
    {
        EmitSignal(SignalName.OnRobotDestroy, robot);
    }


    private void OnMoveEndHandler(Robot robot)
    {
        GameManager.Instance.AllowInput();
        EmitSignal(SignalName.OnRobotMoveEnd, robot);
    }

    public Robot CreatePlayerRobot(LevelRobotModel item)
    {
        var robot = CreateRobot(Global.RobotModelDic[item.RobotTemplateID], Global.PilotModelDic[item.PilotTemplateID], true, false, item.Level);
        robot.PrevPos = robot.Position = MapManager.MapToLocal(new Vector2I(item.X, item.Y));
        return robot;
    }

    public void CreatePlayerRobots(List<LevelRobotModel> list)
    {
        foreach (var item in list)
        {
            CreatePlayerRobot(item);
        }
    }

    public Robot CreateAllyRobot(LevelRobotModel item)
    {
        var robot = CreateRobot(Global.RobotModelDic[item.RobotTemplateID], Global.PilotModelDic[item.PilotTemplateID], false, true, item.Level);
        robot.PrevPos = robot.Position = MapManager.MapToLocal(new Vector2I(item.X, item.Y));
        return robot;
    }
    public void CreateAllyRobots(List<LevelRobotModel> list)
    {
        foreach (var item in list)
        {
            CreateAllyRobot(item);
        }
    }

    public Robot CreateEnemyRobot(LevelRobotModel item)
    {
        var robot = CreateRobot(Global.RobotModelDic[item.RobotTemplateID], Global.PilotModelDic[item.PilotTemplateID], false, false, item.Level);
        robot.Behavior = item.Behavior;
        robot.PrevPos = robot.Position = MapManager.MapToLocal(new Vector2I(item.X, item.Y));
        switch (robot.Behavior)
        {
            case RobotAIBehavior.Guard:
                robot.AddChild(AI_GUARD.Instantiate<GuardAIComponent>());
                break;
            case RobotAIBehavior.Initiative:
                robot.AddChild(AI_INITIATIVE.Instantiate<InitiativeAIComponent>());
                break;
        }
        return robot;
    }

    public void CreateEnemyRobots(List<LevelRobotModel> list)
    {
        foreach (var item in list)
        {
            CreateEnemyRobot(item);
        }
    }

    public void CreateLevelRobots(LevelModel cfg)
    {
        CreateEnemyRobots(cfg.EnemyList);
        CreateAllyRobots(cfg.AllyList);
        CreatePlayerRobots(cfg.PlayerList);
    }

    public static void MoveRobot(Vector2I tarPos, Robot robot, BaseMapManager map)
    {
        GameManager.Instance.LockInput();
        var tarGrid = map.MoveGridList.Find(v => v.MapPos == tarPos);
        var list = new List<MoveGrid>();
        while (tarGrid.Previous != null)
        {
            list.Add(tarGrid);
            tarGrid = tarGrid.Previous;
        }
        list.Reverse();
        map.HideGrids();
        robot.MoveByPath(list);
    }

    public void ResetAllRobotAction()
    {
        foreach (var robot in AllRobotList)
        {
            robot.SetRobotActionEnd(false);
        }
    }

    public Robot GetRobotByPilot(int avatar)
    {
        foreach (var robot in AllRobotList)
        {
            if (robot.Entity.Pilot.Avatar == avatar)
            {
                return robot;
            }
        }
        return null;
    }

    public List<WeaponEntity> GetCanUseWeapons(Robot robot)
    {
        var list = new List<WeaponEntity>();
        foreach (var wp in robot.Entity.WeaponList)
        {
            var ls = FindCanAttackEnemy(robot, wp);
            if (ls.Count > 0)
            {
                list.Add(wp);
            }
        }
        return list;
    }

    public Robot GetRobotByTemplateId(int id)
    {
        foreach (var robot in AllRobotList)
        {
            if (robot.Entity.TemplateID == id)
            {
                return robot;
            }
        }
        return null;
    }

    internal void RemoveRobot(Robot robot)
    {
        if (robot.IsPlayer)
        {
            PlayerRobots.Remove(robot);
        }
        else if (robot.IsAlly)
        {
            AllyRobots.Remove(robot);
        }
        else
        {
            EnemyRobots.Remove(robot);
        }
        robot.SetRobotActionEnd();
        robot.QueueFree();
    }

    public async Task RobotDeath(Robot robot)
    {
        RemoveRobot(robot);
        explosion.Explode(robot.Position);
        await ToSignal(explosion, nameof(Explosion.ExplosionEnd));
    }

    internal List<Robot> FindEnemyByDistance(Robot cur, int dis)
    {
        if (cur.IsPlayer || cur.IsAlly)
        {
            return EnemyRobots.FindAll(v => v.DistanceTo(cur, MapManager) <= dis);
        }
        else
        {
            return PlayerRobots.FindAll(v => v.DistanceTo(cur, MapManager) <= dis);
        }
    }

    List<Robot> GetSkillAllowList(BaseSkill wp)
    {
        var owner = wp.OwnerRobot;
        if (wp.AllowTarget == SkillAllowTarget.Enemy)
        {
            if (owner.IsPlayer || owner.IsAlly)
            {
                return EnemyRobots;
            }
            else
            {
                return new List<Robot>().Concat(PlayerRobots).Concat(AllyRobots).ToList();
            }
        }
        else if (wp.AllowTarget == SkillAllowTarget.Ally)
        {
            if (owner.IsPlayer || owner.IsAlly)
            {
                return new List<Robot>().Concat(PlayerRobots).Concat(AllyRobots).ToList();
            }
            else
            {
                return EnemyRobots;
            }
        }
        else if (wp.AllowTarget == SkillAllowTarget.All)
        {
            return AllRobotList;
        }
        else if (wp.AllowTarget == SkillAllowTarget.Self)
        {
            return new List<Robot> { owner };
        }
        else
        {
            return null;
        }
    }

    public List<Robot> FindCanAttackEnemy(Robot robot, WeaponEntity wp, List<Robot> tarList = null)
    {
        List<Robot> list = new();
        if (wp == null)
        {
            return list;
        }
        tarList ??= GetSkillAllowList(wp);
        if (wp.CastType == SkillCastType.NoTarget)
        {
            // 目标允许类型
            if (wp.AllowTarget == SkillAllowTarget.Enemy)
            {
                foreach (var e in tarList)
                {
                    var dis = robot.MapDistanceTo(e);
                    // 立即施放的技能 根据 半径 查找攻击范围内的敌人
                    if (dis <= wp.Radius)
                    {
                        // 并且武器能攻击指定类型的敌人
                        if (wp.CanAttackTarget(e))
                        {
                            list.Add(e);
                        }
                    }
                }
            }
            else if (wp.AllowTarget == SkillAllowTarget.Ally)
            {
                foreach (var e in tarList)
                {
                    var dis = robot.MapDistanceTo(e);
                    // 需要目标施放的技能 ， 根据 范围 查找攻击范围内的敌人
                    if (dis <= wp.Radius)
                    {
                        list.Add(e);
                    }
                }
            }
            else if (wp.AllowTarget == SkillAllowTarget.All)
            {
                foreach (var e in tarList)
                {
                    var dis = robot.MapDistanceTo(e);
                    // 需要目标施放的技能 ， 根据 范围 查找攻击范围内的敌人
                    if (dis <= wp.Radius)
                    {
                        list.Add(e);
                    }
                }
            }
        }
        else if (wp.CastType == SkillCastType.Target)
        {
            if (wp.AllowTarget == SkillAllowTarget.Enemy)
            {
                foreach (var e in tarList)
                {
                    var dis = robot.MapDistanceTo(e);
                    // 需要目标施放的技能 ， 根据 范围 查找攻击范围内的敌人
                    if (dis >= wp.RangeMin && dis <= wp.RangeMax)
                    {
                        // 并且武器能攻击指定类型的敌人
                        if (wp.CanAttackTarget(e))
                        {
                            list.Add(e);
                        }
                    }
                }
            }
            else if (wp.AllowTarget == SkillAllowTarget.Ally || wp.AllowTarget == SkillAllowTarget.All)
            {
                foreach (var e in tarList)
                {
                    var dis = robot.MapDistanceTo(e);
                    // 需要目标施放的技能 ， 根据 范围 查找攻击范围内的敌人
                    if (dis >= wp.RangeMin && dis <= wp.RangeMax)
                    {
                        list.Add(e);
                    }
                }
            }
            else if (wp.AllowTarget == SkillAllowTarget.Self)
            {
                list.Add(robot);
            }
        }
        else if (wp.CastType == SkillCastType.Point)
        {

        }
        return list;
    }

    public Dictionary<WeaponEntity, List<Robot>> FindCanAttackEnemy(Robot robot, List<Robot> tarList = null)
    {
        Dictionary<WeaponEntity, List<Robot>> list = new();
        // 根据武器列表查找攻击范围内的敌人
        foreach (var wp in robot.Entity.WeaponList)
        {
            // 根据不同的武器类型查找攻击范围内的敌人
            var ls = FindCanAttackEnemy(robot, wp, tarList);
            if (ls.Count > 0)
            {
                list.Add(wp, ls);
            }
        }
        return list;
    }

    public Dictionary<WeaponEntity, List<Robot>> GetCanAttackEnemyAfterMove(Robot robot, List<MoveGrid> grids)
    {
        var result = new Dictionary<WeaponEntity, List<Robot>>();
        foreach (var wp in robot.Entity.WeaponList)
        {
            // 假设机体移动到 grids 中的任意一个位置
            foreach (var g in grids)
            {
                // 从这个位置开始查找攻击范围内的敌人
                var list = GetEnemyRobotsByWeaponOnTargetGrid(robot, wp, g);
                if (list.Count > 0)
                {
                    if (!result.ContainsKey(wp))
                    {
                        result.Add(wp, list);
                    }
                    else
                    {
                        result[wp].AddRange(list);
                        result[wp] = result[wp].Distinct().ToList();
                    }
                }
            }
        }

        return result;
    }

    static List<Robot> GetEnemyRobotsByWeaponOnTargetGrid(Robot robot, WeaponEntity wp, MoveGrid targetGrid, List<Robot> container = null)
    {
        var list = container ?? new List<Robot>();
        var x = targetGrid.MapX;
        var y = targetGrid.MapY;
        var rangeMax = wp.RangeMax;
        var rangeMin = wp.RangeMin;
        var _grids = MapManager.MoveGrids;
        for (int i = x - rangeMax; i <= x + rangeMax; i++)
        {
            for (int j = y - rangeMax; j <= y + rangeMax; j++)
            {
                // 在攻击范围内 且 格子上有机体
                if (Mathf.Abs(i - x) + Mathf.Abs(j - y) >= rangeMin && Mathf.Abs(i - x) + Mathf.Abs(j - y) <= rangeMax && _grids.GetLength(0) > i && _grids.GetLength(1) > j && _grids[i, j] != null)
                {
                    var tar = _grids[i, j].RobotOnGrid;
                    if (!list.Contains(tar) && tar != null)
                    {
                        if ((robot.IsPlayer || robot.IsAlly) && !tar.IsPlayer && !tar.IsAlly)
                        {
                            list.Add(tar);
                        }
                        else if (!robot.IsPlayer && !robot.IsAlly && (tar.IsPlayer || tar.IsAlly))
                        {
                            list.Add(tar);
                        }
                    }
                }
            }
        }
        return list;
    }

    /// <summary>
	/// 获取最近的一些敌人
	/// </summary>
	/// <param name="robot"></param>
	/// <returns></returns>
	public List<Robot> GetNearestEnemyRobots(Robot robot)
    {
        List<Robot> list = new();
        int range = 9999;
        if (robot.IsPlayer || robot.IsAlly)
        {
            foreach (var item in EnemyRobots)
            {
                var dis = robot.MapDistanceTo(item);
                if (dis < range)
                {
                    list.Clear();
                    list.Add(item);
                    range = dis;
                }
                else if (dis == range)
                {
                    list.Add(item);
                }
            }
        }
        else
        {
            var l = new List<Robot>().Concat(AllyRobots).Concat(PlayerRobots).ToList();
            foreach (var item in l)
            {
                var dis = robot.MapDistanceTo(item);
                if (dis < range)
                {
                    list.Clear();
                    list.Add(item);
                    range = dis;
                }
                else if (dis == range)
                {
                    list.Add(item);
                }
            }
        }
        return list;
    }

    public async Task RobotMoveTo(Robot robot, Vector2I p)
    {
        var path = MapManager.GetRobotMovePath(p);
        path.Reverse();
        robot.MoveByPath(path);
        await ToSignal(robot, nameof(Robot.OnMoveEnd));
    }

    internal Dictionary<WeaponEntity, List<Robot>> GetCanAttackEnemies(Robot self, List<Robot> list = null)
    {
        var result = new Dictionary<WeaponEntity, List<Robot>>();
        foreach (var wp in self.Entity.WeaponList)
        {
            var _list = FindCanAttackEnemy(self, wp, list);
            if (_list.Count > 0)
            {
                result.Add(wp, _list);
            }
        }
        return result;
    }

    List<Robot> sortedEnemyList = new();
    int EnemyIndex = 0;
    private void EnemyRobotActionEndHandler(Robot robot)
    {
        if (levelManager.IsPlayerRonnd) return;
        EnemyIndex++;
        if (EnemyIndex == sortedEnemyList.Count)
        {
            EnemyIndex = 0;
            EmitSignal(SignalName.OnEnemyRoundEnd);
        }
        else
        {
            var current = sortedEnemyList[EnemyIndex];
            if (!current.IsDeath)
            {
                current.RunAI();
            }
            else
            {
                EnemyRobotActionEndHandler(current);
            }
        }
    }
    public void RunEnemyAI()
    {
        // 计算每个敌人和玩家的距离 ， 根据距离远近排序 ，决定行动顺序
        var dic = new Dictionary<Robot, int>();
        var list = PlayerRobots.Concat(AllyRobots).ToList();
        foreach (var enemy in EnemyRobots)
        {
            var dis = 0;
            foreach (var player in list)
            {
                dis = enemy.MapDistanceTo(player);
            }
            if (dic.ContainsKey(enemy))
            {
                if (dic[enemy] > dis)
                {
                    dic[enemy] = dis;
                }
            }
            else
            {
                dic.Add(enemy, dis);
            }
        }
        sortedEnemyList = dic.OrderBy(v => v.Value).OrderBy(v => v.Key.Behavior).Select(v => v.Key).ToList();
        if (sortedEnemyList.Count > 0)
        {
            sortedEnemyList[EnemyIndex].RunAI();
        }
    }

    public void RoundStartActions()
    {
        ResetAllRobotAction();
        RecoverActionOnRoundStart();
        BuffRoundStartActions();
    }

    private void BuffRoundStartActions()
    {
        foreach (var item in AllRobotList)
        {
            item.BuffRoundStartActions();
        }
    }


    private async void RecoverActionOnRoundStart()
    {
        foreach (var item in AllRobotList)
        {
            if (MapManager.IsRobotOnRecoverBuilding(item))
            {
                Cursor.LookAt(item);
                var amount = Mathf.CeilToInt(item.Entity.TotalHealth * 0.3f);
                VFXManager.VFXWeaponRepair(item.Position, amount);
                await ToSignal(VFXManager, nameof(VFXManager.OnVFXEnd));
                item.TakeHeal(amount);
            }
            // 如果是母舰上的机体 ， 则恢复 30% 的生命
            if (item.Entity.IsMotherShip)
            {
                item.RecoverHealthOnMotherShip();
            }
        }
    }

    public Robot GetMotherShip()
    {
        return PlayerRobots.Find(v => v.Entity.IsMotherShip);
    }

    internal bool IsSamePosAtMotherShip(Robot robot)
    {
        var ms = GetMotherShip();
        if (ms != null && robot != ms)
        {
            return MapManager.LocalToMap(robot.Position) == MapManager.LocalToMap(ms.Position);
        }
        else
        {
            return false;
        }
    }
}
